package com.ruoyi.system.runner;

import com.ruoyi.common.config.AppConfig;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.datasource.MysqlScriptExecutor;
import com.ruoyi.common.datasource.TableExistsChecker;
import com.ruoyi.common.enums.filerecord.FileStatusEnum;
import com.ruoyi.common.enums.filerecord.FileTypeEnum;
import com.ruoyi.common.enums.filerecord.IsExecuteEnum;
import com.ruoyi.common.enums.filerecord.StorageTypeEnum;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.domain.vo.FileRecordVO;
import com.ruoyi.system.service.IFileRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
@Slf4j
@Order(2) // 数值越小，优先级越高
public class MysqlInitTableRunner implements ApplicationRunner {

    TableExistsChecker tableExistsChecker = SpringUtils.getBean(TableExistsChecker.class);

    MysqlScriptExecutor mysqlScriptExecutor = SpringUtils.getBean(MysqlScriptExecutor.class);

    // 注入我们配置的线程池（通过@Qualifier指定名称）
    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private Executor customThreadPool;

    @Autowired
    private IFileRecordService fileRecordService;


    @Autowired
    private RedisCache redisCache;

    @Override
    public void run(ApplicationArguments args){

        log.info("MysqlInitTableRunner run");
        boolean file_record = tableExistsChecker.isTableExists("file_record", AppConfig.SYS_DB_NAME);

        if (!file_record) {
            // 执行建表语句
            // 执行脚本  create_file_record.sql
            String projectRootPath = redisCache.getCacheObject(CacheConstants.PROJECT_ROOT_PATH);

            if(StringUtils.isNotEmpty(projectRootPath)){

                String sqlPath = projectRootPath + File.separator + "sql-zy";
                log.info("MysqlInitTableRunner sqlPath:{}" ,sqlPath);
                // 特殊处理 create_file_record.sql脚本

                List<Path> fileList = FileUtils.getDirFile(Paths.get(sqlPath), false,true);
                for (Path path : fileList) {
                    String pathStr = path.toString();
                    if("create_file_record.sql".equals(FileUtils.getName(pathStr))){

                        // 执行脚本
                        try {
                            MysqlScriptExecutor.ExecutionResult executionResult = mysqlScriptExecutor.executeClassPathScript(pathStr);
                            if(executionResult.getSuccess() == 1){
                                log.info("MysqlInitTableRunner create_file_record.sql 执行成功");

                                FileRecordVO fileRecordVO = new FileRecordVO();

                                File file = new File(pathStr);
                                if(!file.exists()){
                                    log.error("MysqlInitTableRunner " + pathStr + " 文件不存在");
                                    continue;
                                }
                                setFileRecordVOInfo(fileRecordVO, file);
                                fileRecordVO.setIsExecute(IsExecuteEnum.EXECUTE.getCode());
                                fileRecordService.insertFileRecord(fileRecordVO);
                            }else {
                                log.error("MysqlInitTableRunner create_file_record.sql 执行失败");
                            }
                        } catch (IOException | SQLException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }else {
                log.error("MysqlInitTableRunner projectRootPath is null");
            }
        }
        // 执行数据库表字段 增删改查操作
        String projectRootPath = redisCache.getCacheObject(CacheConstants.PROJECT_ROOT_PATH);
        if(StringUtils.isNotEmpty(projectRootPath)) {

            String sqlPath = projectRootPath + File.separator + "sql-zy";
            List<Path> firstLevelDirList = FileUtils.getDirFile(Paths.get(sqlPath), true,true);

            Map<String, FileRecordVO> fileRecordVOMap = getFileRecordVOMap();

            // 自定义Comparator：提取文件名中的日期并升序排序
            Comparator<Path> dateComparator = Comparator.comparing(path -> {
                String fileName = path.getFileName().toString();
                // 正则表达式提取yyyyMMdd格式的日期（假设日期在文件名中是唯一的连续8位数字）
                Pattern pattern = Pattern.compile("(\\d{8})");
                Matcher matcher = pattern.matcher(fileName);
                if (matcher.find()) {
                    return matcher.group(1); // 返回日期字符串，如"20250915"
                }
                return ""; // 无日期时按空字符串排序（可根据需求调整）
            });
            firstLevelDirList.sort(dateComparator);

            for (Path firstDirPath : firstLevelDirList) {

                List<Path> secLevelDirList = FileUtils.getDirFile(firstDirPath, false,true);
                // 自定义Comparator：提取文件名中的日期并升序排序
                Comparator<Path> numberComparator = Comparator.comparing(path -> {
                    String fileName = FileUtils.getName(path.toString());
                    String[] split = fileName.split("_");
                    if(!split[0].startsWith("create")){
                        return Integer.parseInt(split[0]); // 无日期时按空字符串排序（可根据需求调整）
                    }else {
                        return 0;
                    }
                });

                secLevelDirList.sort(numberComparator);
                log.info("MysqlInitTableRunner secLevelDirList 排序后:{}",secLevelDirList);

                customThreadPool.execute(() -> {
                    handleSQLScript(secLevelDirList, fileRecordVOMap);
                });
            }
        }
    }

    private Map<String, FileRecordVO> getFileRecordVOMap() {
        List<FileRecordVO> fileRecords = fileRecordService.queryFileRecordList(null);
        Map<String, FileRecordVO> fileRecordVOMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(fileRecords)){
            fileRecordVOMap = fileRecords.stream().collect(Collectors.toMap(FileRecordVO::getFileName, v -> v));
        }
        return fileRecordVOMap;
    }

    private void handleSQLScript(List<Path> thirdLevelFileList,Map<String, FileRecordVO> fileRecordVOMap) {
        List<FileRecordVO> insertFileRecordVOList = new ArrayList<>();
        List<FileRecordVO> updateFileRecordVOList = new ArrayList<>();
        for (Path path : thirdLevelFileList) {
            try {
                String fileName = FileUtils.getName(path.toString());
                log.info("MysqlInitTableRunner handleSQLScript fileName:{}",fileName);
                if (fileRecordVOMap.containsKey(fileName) && IsExecuteEnum.EXECUTE.getCode().equals(fileRecordVOMap.get(fileName).getIsExecute())) {
                    continue;
                }

                String scriptFile = path.toString();

                File file = new File(scriptFile);
                if(!file.exists()){
                    log.error("MysqlInitTableRunner " + scriptFile + " 文件不存在");
                    continue;
                }
                FileRecordVO fileRecordVO = new FileRecordVO();
                setFileRecordVOInfo(fileRecordVO, file);

                MysqlScriptExecutor.ExecutionResult executionResult = mysqlScriptExecutor.executeClassPathScript(scriptFile);
                fileRecordVO.setIsExecute(IsExecuteEnum.EXECUTE.getCode());
                if(executionResult.getSuccess() == executionResult.getTotal()){
                    log.info("MysqlInitTableRunner " + path.getFileName() + " 执行成功");

                    if (fileRecordVOMap.containsKey(fileRecordVO.getFileName())) {
                        FileRecordVO recordVO = fileRecordVOMap.get(fileRecordVO.getFileName());
                        recordVO.setIsExecute(IsExecuteEnum.EXECUTE.getCode());
                        recordVO.setErrorMsg(null);
                        updateFileRecordVOList.add(recordVO);
                    }else {
                        insertFileRecordVOList.add(fileRecordVO);
                    }
                }else {
                    fileRecordVO.setErrorMsg(String.valueOf(executionResult.getErrors()));
                    log.error("MysqlInitTableRunner " + path.getFileName() + " 执行失败");
                    if (fileRecordVOMap.containsKey(fileRecordVO.getFileName())) {
                        FileRecordVO recordVO = fileRecordVOMap.get(fileRecordVO.getFileName());
                        recordVO.setIsExecute(IsExecuteEnum.EXECUTE.getCode());
                        String exeLog = "[success count :"+executionResult.getSuccess() + "] [failed count :"+executionResult.getFailedSqls().size() + "] errorMsg :"+fileRecordVO.getErrorMsg();
                        recordVO.setErrorMsg(exeLog);
                        updateFileRecordVOList.add(recordVO);
                    }else {
                        insertFileRecordVOList.add(fileRecordVO);
                    }
                }
            }catch (IOException | SQLException e){
                log.error("MysqlInitTableRunner " + path.getFileName() + " 执行失败");
            }
        }

        // 批量插入
        fileRecordService.saveBathEntity(insertFileRecordVOList);

        // 批量更新
        fileRecordService.updateBatchByIds(updateFileRecordVOList);

    }

    private void setFileRecordVOInfo(FileRecordVO fileRecordVO, File file) throws IOException {
        BasicFileAttributes basicFileAttributes = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
        if (basicFileAttributes.isRegularFile()) {

            fileRecordVO.setFileName(file.getName());
            fileRecordVO.setFilePath(file.getPath());
            fileRecordVO.setFileType(FileTypeEnum.SQL.getCode());
            fileRecordVO.setFileHash(IdUtils.simpleUUID());
            fileRecordVO.setStorageType(StorageTypeEnum.LOCAL.getCode());
            fileRecordVO.setSize(basicFileAttributes.size());
            fileRecordVO.setStatus(FileStatusEnum.NORMAL.getCode());
            fileRecordVO.setIsExecute(IsExecuteEnum.NO_EXECUTE.getCode());
            fileRecordVO.setIsDeleted(0);
            fileRecordVO.setVersion(1);
            fileRecordVO.setCreator("system");
            fileRecordVO.setUpdater("system");
            fileRecordVO.setUpdateTime(new Date());
            fileRecordVO.setCreateTime(new Date());
        }
    }


}
